package com.cata.mall.common.exception;

import cn.hutool.core.util.StrUtil;
import com.cata.mall.common.api.CommonResult;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.sql.SQLSyntaxErrorException;

/**
 * @作者: Tao
 * @日期: 2025/10/10
 * @时间: 15:59
 * @描述: 全局异常处理类<pre>
 */
@ControllerAdvice //定义全局异常处理类
public class GlobalExceptionHandler {

    /**
     * 处理API异常的全局异常处理器
     * <p>
     * 当系统抛出ApiException异常时，该方法会捕获并处理异常，
     * 根据异常中包含的错误码或错误信息，返回统一格式的错误响应结果。
     *
     * @param e ApiException异常实例，包含错误信息或错误码
     * @return CommonResult 统一响应结果，包含失败状态和错误信息
     */
    @ResponseBody
    @ExceptionHandler(value = ApiException.class)
    public CommonResult handle(ApiException e) {
        // 如果异常中包含错误码，则使用错误码构建失败响应
        if (e.getErrorCode() != null) {
            return CommonResult.failed(e.getErrorCode());
        }
        // 否则使用异常消息构建失败响应
        return CommonResult.failed(e.getMessage());
    }

    /**
     * 处理方法参数验证异常
     * 当控制器方法的参数验证失败时，会抛出MethodArgumentNotValidException异常，该方法用于捕获并处理此异常
     * @param e 方法参数验证异常对象，包含验证失败的详细信息
     * @return 返回封装的验证失败结果，包含具体的错误信息
     */
    @ResponseBody
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public CommonResult handleValidException(MethodArgumentNotValidException e) {
        // 获取绑定结果，包含验证错误信息
        BindingResult bindingResult = e.getBindingResult();
        String message = null;

        // 检查是否存在验证错误
        if (bindingResult.hasErrors()) {
            // 获取第一个字段错误信息
            FieldError fieldError = bindingResult.getFieldError();
            if (fieldError != null) {
                // 拼接字段名和错误信息
                message = fieldError.getField()+fieldError.getDefaultMessage();
            }
        }

        // 返回验证失败的通用结果
        return CommonResult.validateFailed(message);
    }

    /**
     * 处理数据绑定异常的全局异常处理器
     * 当控制器方法参数绑定失败时（如@RequestParam、@RequestBody等），会抛出BindException异常，
     * 该方法用于捕获并处理此类异常，返回统一的验证失败结果
     *
     * @param e BindException类型的异常对象，包含数据绑定过程中的错误信息
     * @return CommonResult 包含验证失败信息的通用返回结果对象
     */
    @ResponseBody
    @ExceptionHandler(value = BindException.class)
    public CommonResult handleValidException(BindException e) {
        // 获取绑定结果，从中提取具体的字段错误信息
        BindingResult bindingResult = e.getBindingResult();
        String message = null;

        // 检查是否存在绑定错误，并提取第一个字段错误的详细信息
        if (bindingResult.hasErrors()) {
            FieldError fieldError = bindingResult.getFieldError();
            if (fieldError != null) {
                message = fieldError.getField()+fieldError.getDefaultMessage();
            }
        }

        return CommonResult.validateFailed(message);
    }


    /**
     * 处理SQL语法异常的全局异常处理器
     * 当系统捕获到SQLSyntaxErrorException异常时，会调用此方法进行统一处理
     * @param e SQL语法异常对象
     * @return 包含错误信息的通用返回结果对象
     */
    @ResponseBody
    @ExceptionHandler(value = SQLSyntaxErrorException.class)
    public CommonResult handleSQLSyntaxErrorException(SQLSyntaxErrorException e) {
        String message = e.getMessage();
        // 判断是否为权限拒绝相关的SQL异常，如果是则返回友好的提示信息
        if (StrUtil.isNotEmpty(message) && message.contains("denied")) {
            message = "演示环境暂无修改权限，如需修改数据可本地搭建后台服务！";
        }
        return CommonResult.failed(message);
    }


}
